home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
msdos
/
viewers
/
showgl19
/
hpgl1.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-18
|
35KB
|
1,232 lines
#pragma linesize(132) /* listing linewidth = 132 */
/* hpgl1.c */
/* This code Copyright 1991, 1992, Robert C. Becker, Lantern Systems */
/* rev. E 8/16/92
Added solid line fill type to filled rectangles. Also added new window
window clipper. It was needed for solid fill type because we do direct
access to pw_wrt_line () in the graphix library. This routine also cleaned
up some of the clipping code in showhpgl.c and fixed a few bugs related to
drawing outside the P1/P2 hard clip if IW was defined larger than the
hard clip border
*/
/* rev. D 8/13/92
Relocated some code from hpgl1.c to hpgl2.c to make file sizes more
equal and reduce compile time of hpgl1.c . */
/* Rev. C. 8/8/92
Found and fixed bugs in tick mark calculation and filled rectangles. The tick
mark bug manifested itself as not resizing tick sizes when P1/P2 changed. Part
of the fix is in showhpgl.c . Added recalc_ticksize ().
Found and fixed bug in filled rectangle drawing routines. Fixed logic errors
in fill_type () which assigned the wrong units when default spacing was in
effect. fill_rect () attempted to draw in plotter units even if user unit
scaling was in effect.
*/
/* Rev. B. 8/2/92
Found a bug in tick mark drawing routines. In order to simplify the need
to draw in a consistent size unit based on the P1/P2 spacings, the tick size
was calculated in GDU's and the drawing mode was changed from UDU's to GDU's.
This, unfortunately, reset the clip border to the hardclip limit, instead of
the UDU border and allowed ticks to be drawn outside the soft clip border.
calc_ticksize () has been changed to calculate tick sizes in plotter units,
and two other variables (uu_2_pux, uu_2_puy) which are calculated every time
set_scale () is called convert from user units to ploter units depending on
scaling = ON/OFF.
*/
/* Rev. A. */
/* This file contains the following functions:
arc_3pt ()
calc_ticksize ()
chord_t ()
circle ()
cot ()
draw_xtick ()
draw_ytick ()
draw_rect ()
fill_rect ()
fill_type ()
fix_hatch ()
init_fills ()
new_plot ()
plotted_on ()
print_error ()
recalc_ticksize ()
tick_length ()
velocity_sel ()
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include "graph.h" /* this must preceed hpgl.h */
#include "mscio.h" /* header for pc_wrt_line () */
#include "gstructs.h" /* header file for library structures */
#include "hpgl.h"
extern struct hp_misc __gr_msc__; /* library struct */
extern struct clip_border hpgl_clip;
extern int my_pen;
extern int scaling;
extern double p1x, p1y, p2x, p2y;
extern int chord_type, p_status, symbol_mode;
extern double uu_2_pux, uu_2_puy;
extern char symbol;
extern int debugging;
static void fill_rect (double, double, double, double, double, double);
static double cot ( double );
static void solid_rect ( double, double, double, double );
static int code ( int, int);
static char copyright[] = "Copyright 1991, 1992, Robert C. Becker, Lantern Systems";
struct poly_fills
{
int mode;
double opt1, opt2;
double alt_opt1;
};
static struct poly_fills fill_code [6]; /* hold values for types 1, 2, 3, 4, 10, 11 */
/* values for these type stored in this order in struct array */
struct tick
{
double tnx, tny, tpx, tpy, tn, tp;
/* x, y tick negative & positive lengths in plotter units; tx, ty in % */
};
static struct tick ticksize;
static int select_fill; /* last fill type selected */
static double anchor_x, anchor_y; /* corner anchors for fill types */
static int dirty_plot; /* flag to mark if plot has been plotted on yet */
/*--------------------------------------*/
void velocity_sel (FILE *infile)
{
double x;
DB (printf ("VS\n");)
if (get_val (infile, &x)) /* optional speed argument: not used */
{
get_val (infile, &x); /* optional pen # argument: not used */
}
return;
}
/*--------------------------------------*/
void tick_length (FILE *infile)
{
double tp, tn;
tp = DEF_TICK;
tn = DEF_TICK; /* default tick lengths */
if ( get_val (infile, &tp)) /* got one value: try for two */
{
if (!get_val (infile, &tn)) tn = 0.0; /* if only have one value, tn = 0 */
}
calc_ticksize (tp, tn);
return;
}
/*--------------------------------------*/
void recalc_ticksize ( void )
{
/* force recalculation of ticksize when P1/P2 change */
calc_ticksize (ticksize.tp, ticksize.tn);
return;
}
/*--------------------------------------*/
void calc_ticksize (double tp, double tn)
{
tp = MAX (-100.0, (MIN (100.0, tp)));
tn = MAX (-100.0, (MIN (100.0, tn))); /* limit tick size to +/- 100% */
ticksize.tp = tp;
ticksize.tn = tn; /* save tick lengths */
/* calculate tick lengths (plotter units) for x- and y-axes */
ticksize.tpx = tp * fabs (p2x - p1x) / 100.0;
ticksize.tpy = tp * fabs (p2y - p1y) / 100.0;
ticksize.tnx = tn * fabs (p2x - p1x) / 100.0;
ticksize.tny = tn * fabs (p2y - p1y) / 100.0;
/* P1, P2 are in mils (plotter units) */
DB (printf ("calc_ticksize: tpx = %lf, tnx = %lf, tpy = %lf, tny = %lf\n", \
ticksize.tpx, ticksize.tnx, ticksize.tpy, ticksize.tny);)
return;
}
/*--------------------------------------*/
void draw_xtick (void)
{
double x_1, y_1;
double ystart, ystop; /* local variables */
/* move relative to current position. Convert plotter units to user
units if required */
ystart = -ticksize.tny;
ystop = ticksize.tpy; /* start & stop points in plotter units */
if (scaling == ON) /* start & stop points in user units */
{
ystart = -ticksize.tny * uu_2_puy;
ystop = ticksize.tpy * uu_2_puy;
}
where (&x_1, &y_1); /* get starting position */
DB (printf ("draw_xtick: scaling = %d, ystart = %lf, ystop = %lf\n", \
scaling, ystart, ystop);)
rmove (0.0, ystart); /* move relative to current position */
rdraw (0.0, ystop); /* draw vertical tick mark */
move (x_1, y_1); /* re-establish original position */
plotted_on (1); /* we drew something on this plot */
return;
}
/*--------------------------------------*/
void draw_ytick (void)
{
double x_1, y_1;
double xstart, xstop; /* local variables */
/* move relative to current position. Convert plotter units to user
units if required */
xstart = -ticksize.tnx;
xstop = ticksize.tpx; /* start & stop points in plotter units */
if (scaling == ON) /* start & stop points in user units */
{
xstart = -ticksize.tnx * uu_2_pux;
xstop = ticksize.tpx * uu_2_pux;
}
where (&x_1, &y_1);
DB (printf ("draw_ytick: scaling = %d, xstart = %lf, xstop = %lf\n", \
scaling, xstart, xstop);)
rmove (xstart, 0.0);
rdraw (xstop, 0.0); /* draw horizontal tick mark */
move (x_1, y_1); /* re-establish original position */
plotted_on (1); /* we drew something on this plot */
return;
}
/*--------------------------------------*/
void print_error (char *instr, int type)
{
if (!debugging) return; /* no output if not asked for */
if (type)
fprintf (stdout, "%s", instr);
else
fprintf (stdout, "%s instruction not implimented\n", instr);
return;
}
/*--------------------------------------*/
void new_plot ( void )
{
dirty_plot = 0; /* plot is clean (not plotted on) */
return;
}
/*--------------------------------------*/
int plotted_on (int plot_flag)
{
if (plot_flag > 0)
dirty_plot = 1; /* mark plot as plotted on */
return (dirty_plot);
}
/*--------------------------------------*/
void circle (FILE * infile)
{
double ang, ang2, radius, val2, x_1, y_1;
unsigned char c2;
int segs;
DB(printf ("CI\n");)
if (!get_val (infile, &radius))
{
print_string ("CI: radius not specified\n");
return; /* error: no param's */
}
ang2 = val2 = DEF_CHORD; /* default chord angle or deviation for circle/arc */
if ( get_val (infile, &val2))
{
val2 = fabs (val2); /* only positive values allowed */
if (chord_type == ANG || val2 == 0.0) /* using angles, not deviations */
{
if (val2 == 0.0) val2 = DEF_CHORD; /* set default chord angle or deviation */
ang2 = MIN (MAX_CHORD, (MAX (val2, MIN_CHORD)));
}
else /* chord angle determined by deviation of segments from circle radius */
{ /* at this point, val2 is length in current units, not angle in degrees */
if (val2 > 2.0 * radius) val2 = 2.0 * radius; /* limit deviation: resulting chord angle < 180 deg. */
ang2 = acos ( (radius - val2) / radius) * RAD_2_DEG;
}
}
segs = (int) (360.0 / ang2 + 0.5); /* # segments in 360 deg. */
/* sign of 'segs' changes direction of arc () */
DB (printf ("CI: radius = %lf, chord = %lf, # segments = %d\n", radius, ang2, segs);)
where (&x_1, &y_1);
arc (radius, segs, 0.0, 360.0); /* circle with l segments */
if (symbol_mode)
{
move (x_1, y_1);
symbol_mark (symbol);
}
plotted_on (1); /* we drew something on this plot */
return;
}
/*--------------------------------------*/
void arc_3pt (FILE * infile, int type)
{ /* type 0 = absolute arc, type 1 = relative arc */
double ma, mb, ba, bb, x_1, y_1, xi, yi, xe, ye;
double dax, day, dbx, dby, xc, yc, ang_e, ang_i;
double start_ang, stop_ang, radius, ang2, val5;
int segs, cw;
DB (if (type == RELATIVE) printf ("AR\n"); else printf ("AT\n");)
if (!get_xy (infile, &xi, &yi))
{
if (type == RELATIVE)
print_string ("AR: missing Xi or Yi value\n");
else
print_string ("AT: missing Xi or Yi value\n");
return;
}
if (!get_xy (infile, &xe, &ye))
{
if (type == RELATIVE)
print_string ("AR: missing Xe or Ye value\n");
else
print_string ("AT: missing Xe or Ye value\n");
return;
}
where (&x_1, &y_1); /* current position */
if (type == RELATIVE) /* relative arc in 3 pts */
{
xe += x_1;
ye += y_1;
xi += x_1;
yi += y_1; /* convert from offsets to abs coordinates */
}
dax = xe - x_1;
day = ye - y_1; /* delta-x, -y from ref. to end pt. */
dbx = xi - xe;
dby = yi - ye; /* delta-x, -y from end pt. to intermediate pt. */
DB (printf ("P1: (%lf, %lf) Pi: (%lf, %lf), Pe: (%lf, %lf)\n", x_1, y_1, xi, yi, xe, ye);)
DB (printf ("fabs (day) = %lf, fabs(dby) = %lf\n", fabs(day), fabs(dby));)
if ( fabs (day) < FLT_EPSILON) /* P1, Pe horizontal or same */
{ /* FLT, not DBL: more conservative */
DB (printf ("fabs (day) < FLT_EPSILON\n");)
xc = x_1 + dax / 2; /* equation of vertical line */
if (fabs (dby) < FLT_EPSILON || fabs (dax) < FLT_EPSILON)
{ /* all pts horizontal */
DB (printf ("vertical or straight line curve\n");)
if (symbol_mode)
{
move (x_1, y_1);
symbol_mark (symbol);
}
draw (xi, yi); /* draw intermediate pt in case end & start same */
draw (xe, ye); /* this is the curve */
plotted_on (1); /* we drew something on this plot */
return;
}
mb = -dbx / dby; /* slope of line normal to PePi */
bb = (ye + dby / 2) - mb * (xe + dbx / 2); /* now have b-part of line equations */
yc = mb * xc + bb;
}
else
{ /* FLT, not DBL: more conservative */
if (fabs (dby) < FLT_EPSILON) /* Pe, Pi horizontal or same */
{
DB (printf ("fabs (dby) < FLT_EPSILON\n");)
xc = xe + dbx / 2; /* equation of vertical line */
if (fabs (day) < FLT_EPSILON || fabs (dbx) < FLT_EPSILON)
{ /* all pts horizontal or Pe == Pi */
DB (printf ("horizontal or straight line curve\n");)
if (symbol_mode)
{
move (x_1, y_1);
symbol_mark (symbol);
}
draw (xi, yi); /* draw intermediate pt in case end & start same */
draw (xe, ye); /* this is the curve */
plotted_on (1); /* we drew something on this plot */
return;
}
ma = -dax / day; /* slope of line normal to PiPe */
ba = (y_1 + day / 2) - ma * (x_1 + dax / 2);
yc = ma * xc + ba;
}
else
{
/* general case: can't handle dby = 0 or day = 0 */
ma = -dax / day; /* slope of line normal to P1Pe */
mb = -dbx / dby; /* slope of line normal to PePi */
/* y_1 + day = y-value midway between y_1 and ye */
/* x_1 + dax = x-value midway between x_1 and xe */
/* ye + dby = y-value midway between ye and yi */
/* xe + dbx = x-value midway between xe and yi */
ba = (y_1 + day / 2) - ma * (x_1 + dax / 2);
bb = (ye + dby / 2) - mb * (xe + dbx / 2); /* now have b-part of line equations */
if (fabs (ma - mb) < FLT_EPSILON) /* that's right FLT, not DBL */
{ /* too small to prevent floating point overflow */
DB (printf ("straight line curve\n");)
if (symbol_mode)
{
move (x_1, y_1);
symbol_mark (symbol);
}
draw (xi, yi); /* draw intermediate pt in case end & start same */
draw (xe, ye); /* this is the curve */
return;
}
xc = (bb - ba) / (ma - mb); /* now have x-center */
yc = mb * xc + bb; /* can find yc using either line eqn. */
}
}
DB (printf ("3-pt. arc: center at (%lf, %lf)\n", xc, yc);)
radius = sqrt ((xc - x_1) * (xc - x_1) + (yc - y_1) * (yc - y_1));
val5 = ang2 = DEF_CHORD;
if (get_val (infile, &val5))
{
val5 = fabs (val5); /* only positive values allowed */
/* note: if no tolerance is specified, the default is a
chord ANGLE of 5 DEGREES, regardless of chord_type */
if (chord_type == ANG || val5 == 0.0) /* using angles, not deviations */
{
if (val5 == 0.0) val5 = DEF_CHORD; /* set default chord angle */
ang2 = MIN (MAX_CHORD, (MAX (val5, MIN_CHORD)));
}
else /* chord angle determined by deviation of segments from circle radius */
{ /* at this point, val5 is length in current units, not angle in degrees */
if (val5 > 2.0 * radius) val5 = 2.0 * radius; /* limit deviation: resulting chord angle < 180 deg. */
ang2 = acos ( (radius - val5) / radius) * RAD_2_DEG;
/* note that this value is being left in radians (for now) */
}
}
DB (printf ("P1: (%lf, %lf), Pc: (%lf, %lf), Pe: (%lf, %lf)\n", x_1, y_1, xc, yc, xe, ye);)
start_ang = RAD_2_DEG * atan2 (y_1 - yc, x_1 - xc); /* angle from center to starting pt */
stop_ang = RAD_2_DEG * atan2 (ye - yc, xe - xc); /* angle from center to stopping pt */
DB (printf ("initial: start_ang = %lf, stop_ang = %lf\n", start_ang, stop_ang);)
ang_e = RAD_2_DEG * atan2 (day, dax);
ang_i = RAD_2_DEG * atan2 ( yi - y_1, xi - x_1); /* determine direction of arc */
cw = 1; /* direction defaults to clockwise rotation */
if (ang_e >= 0.0 && ang_i >= 0.0) /* resolve direction of arc by */
cw = (ang_e < ang_i) ? 1 : 0; /* angle between ref. pt and other 2 pts */
else
{
if (ang_e <= 0.0 && ang_i <= 0.0)
cw = (ang_e < ang_i) ? 1 : 0;
else
{
if (ang_e <= 0.0 && ang_i >= 0.0) /* first conflict */
cw = (ang_i - ang_e <= 180.0) ? 1 : 0;
else
if (ang_e >= 0.0 && ang_i <= 0.0)
cw = (ang_e - ang_i >= 180.0) ? 1 : 0;
}
}
/* now we have determined which direction the arc is drawn (either cw or ccw) */
switch (cw)
{
case 0: /* counter clockwise rotation */
DB (printf ("counter-clockwise rotation\n");)
if (start_ang >= 0.0 && stop_ang >= 0.0)
{
stop_ang += (start_ang > stop_ang) ? 360.0 : 0.0; /* 1 */
}
else
{
if (start_ang <= 0.0 && stop_ang <= 0.0)
{
stop_ang += (start_ang > stop_ang) ? 360.0 : 0.0; /* 2 */
}
else
if (start_ang >= 0.0 && stop_ang <= 0.0) /* 4 */
{
stop_ang += 360.0;
}
}
break;
case 1: /* clockwise rotation */
DB (printf ("clockwise rotation\n");)
if (stop_ang >= 0.0 && stop_ang >= 0.0)
{
stop_ang -= (start_ang < stop_ang) ? 360.0 : 0.0; /* 1a */
}
else
{
if (start_ang <= 0.0 && stop_ang <= 0.0)
{
stop_ang -= (start_ang < stop_ang) ? 360.0 : 0.0; /* 2a */
}
else
if (start_ang <= 0.0 && stop_ang >= 0.0) /* 4a */
{
stop_ang -= 360.0;
}
}
break;
default: break;
}
segs = (int) (fabs (start_ang - stop_ang) / ang2 + 0.5); /* # segments in "ang1" deg. */
/* sign of 'segs' changes direction of arc () */
DB (printf ("final: start_ang = %lf, stop_ang = %lf\n", start_ang, stop_ang);)
DB (printf ("chord angle = %lf, # segments = %d\n", ang2, segs);)
move (xc, yc); /* move to center of arc */
arc (radius, segs ,start_ang, stop_ang);
plotted_on (1); /* we drew something on this plot */
return;
}
/*--------------------------------------*/
void init_fills (void)
{ /* only need to initialize hatched & x-hatched fills */
/* values for hatched fill and cross-hatched fill */
/* for DEFAULTUNITS, spacing must be determined at the same time
the fill is used for drawing since P1 & P2 could have changed */
fill_code [HATCH].mode = fill_code [XHATCH].mode = DEFAULTUNITS;
/* don't care about either opt1 or alt_opt1 since default unit sizes
are calculated when they are drawn */
fill_code [HATCH].opt1 = fill_code [XHATCH].opt1 = 0.0;
fill_code [HATCH].alt_opt1 = fill_code [XHATCH].alt_opt1 = 0.0;
fill_code [HATCH].opt2 = fill_code [XHATCH].opt2 = 0.0; /* angle = 0 */
select_fill = DEFAULT_FILL; /* select default fill */
return;
}
/*--------------------------------------*/
void fix_hatch ( void )
{
/* don't care if scaling is on or off. This only affects hatch sizes
when they are in user units and the scale changes */
/* fill_code [].opt1 is in user units; fill_code [].alt_opt1 is in plotter units */
if (fill_code [HATCH].mode == USERUNITS)
fill_code [HATCH].alt_opt1 = fill_code [HATCH].opt1 / uu_2_pux;
if (fill_code [XHATCH].mode == USERUNITS)
fill_code [XHATCH].alt_opt1 = fill_code [XHATCH].opt1 / uu_2_pux;
return;
}
/*--------------------------------------*/
void fill_type (FILE *infile, int scaling )
{
double ftype, opt1, opt2;
int f1, f2, type;
f1 = f2 = 0; /* no arguments */
opt1 = opt2 = 0.0;
if (get_val (infile, &ftype))
{
/* test for invalid type */
if (ftype < 1.0 || ftype > 11.0 || (ftype > 4.0 && ftype < 10.0))
{
while (get_val (infile, &opt1)); /* dump trailing arguments */
return;
}
/* have one value argument */
if (get_val (infile, &opt1))
{
f1 = 1; /* mark option #1 present */
if (get_val (infile, &opt2))
f2 = 1; /* mark option #2 present */
}
type = (int) ftype;
type = (type > 4) ? (type - 6) : type - 1; /* shift range to 0 - 5 */
}
else
{
select_fill = type = DEFAULT_FILL; /* no fill-type -> default */
/* save current fill-type in select_fill */
fill_code [type].mode = DEFAULTUNITS;
/* calculate size of units when fill is drawn */
return;
}
switch (type)
{
case SOLID: /* solid fill: bidirectional */
case SOLID1: /* solid_fill: unidirectional */
select_fill = type; /* save current fill-type */
/* no other information required */
break;
case HATCH: /* hatched fill */
case XHATCH: /* crosshatched fill */
select_fill = type; /* save current fill-type */
if (f1) /* option #1 is present */
{
if (opt1 == 0.0) /* use default spacing */
{
fill_code [type].mode = DEFAULTUNITS;
/* calculate size of units when fill is drawn */
}
else
{
fill_code [type].mode = PLOTTERUNITS; /* assume plotter units */
/* save hatch x-spacing in plotter units */
fill_code [type].alt_opt1 = opt1;
/* don't care about size in user units */
if (scaling == ON)
{
fill_code [type].mode = USERUNITS; /* correct assumption about units */
fill_code [type].opt1 = opt1; /* user units value */
fill_code [type].alt_opt1 = opt1 / uu_2_pux;
/* save value of option #1 in plotter units */
/* we do this because HPGL/2 demands that use units
be frozen in equivalent plotter units if scaling is
turned off */
}
}
/* update angle value only if user supplied */
if (f2) fill_code [type].opt2 = opt2;
}
break;
case 4: select_fill = type; /* save current fill-type */
/* shaded fill: not yet implimented */
break;
case 5: select_fill = type; /* save current fill-type */
/* user defined fill: not yet implimented */
break;
default: print_string ("FT: Invalid fill type\n");
break;
}
return;
}
/*--------------------------------------*/
void draw_rect (FILE * infile, int type)
{ /* type 0 = absolute, type 1 = relative, 0x10 = absolute, filled,
0x11 = relative, filled */
double xp, yp, xc, yc, x_sp, theta;
DB ({if (type & FILLED_ABS) printf ("%s\n", (type & 1) ? "RR" : "RA");})
DB ({if (!(type & FILLED_ABS)) printf ("%s\n", (type & 1) ? "ER" : "EA");})
where (&xp, &yp); /* get current position */
if (get_xy (infile, &xc, &yc))
{
/* calculate width and height for rectangle () function */
if (type & 1) /* relative rect */
{
xc += xp;
yc += yp; /* calculate opposite corner pos */
}
DB (printf ("Rectangle from (%lf, %lf) to (%lf, %lf)\n", xp, yp, xc, yc);)
rectangle (xp, yp, xc, yc);
plotted_on (1); /* mark plot as dirty */
if (type & 0x10)
{
DB (printf ("filled rectangle: select_fill = %d\n", select_fill);)
if (select_fill != HATCH && select_fill != XHATCH)
{
if (select_fill == SOLID || select_fill == SOLID1)
{
solid_rect ( xp, yp, xc, yc);
return;
}
else
return; /* unsupported fill type */
}
theta = fill_code [select_fill].opt2; /* theta */
/* get current hatch spacing in plotter units */
/* for default units, calculate size now */
DB (printf ("rectangle: theta = %lf, fill_code[select_fill].mode = %d\n", \
theta, fill_code [select_fill].mode);)
switch (fill_code [select_fill].mode)
{
case DEFAULTUNITS:
x_sp = 0.01 * sqrt ( (p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
break;
case PLOTTERUNITS:
case USERUNITS:
x_sp = fill_code [select_fill].alt_opt1;
/* x-spacing is in plotter units */
break;
default: break;
}
if (scaling == ON) /* convert to plotter units */
{
plotter_units (&xp, &yp);
plotter_units (&xc, &yc); /* corner coordinates in plotter units */
}
DB (printf ("draw_rect: filled rect: (xp, yp) = (%lf, %lf), (xc, yx) = (%lf, %lf)\n",\
xp, yp, xc, yc);)
fill_rect (xp, yp, xc, yc, x_sp, theta);
if (select_fill == XHATCH) /* if cross-hatch, draw crossing hatch at theta + 90 */
fill_rect (xp, yp, xc, yc, x_sp, theta + 90.0);
}
return;
}
if (type & 0x10) /* filled */
{
if (type & 1)
print_string ("ER: missing argument\n");
else
print_string ("EA: missing argument\n");
}
else
{
if (type & 1)
print_string ("RR: missing argument\n");
else
print_string ("RA: missing argument\n");
}
return;
}
/*--------------------------------------*/
static void fill_rect (double x_1, double y_1, double x_2, double y_2, double x_sp, double theta)
{ /* x_sp, x_1, x_2, y_1, y_2 all in plotter units */
double ymin, ymax, xmin, xmax;
double xd1, yd1, xd2, yd2, ac_x, ac_y, x_off, xh;
double yh, yi, xi, y_off, xlast, ylast, etan, ecot, theta_r;
int n, sector;
get_anchor (&ac_x, &ac_y); /* get anchor corner in plotter units */
xmin = x_1;
ymin = y_1;
xmax = x_2;
ymax = y_2;
DB (printf ("hatch_fill: x_sp = %lf, theta = %lf\n", x_sp, theta);)
theta = fmod (theta, 180.0);
theta_r = theta / RAD_2_DEG;
if (theta < 90.0)
{ /* sectors 1,5 */
if (theta < 45.0)
{
sector = 1;
yi = (x_1 - ac_x) * tan (theta_r) + ac_y;
yh = x_sp / cos (theta_r); /* this fails at theta = 90 */
y_off = fmod (y_2 - yi, yh); /* get distance below top edge for starting point */
y_1 = ymax - y_off;
if (y_1 > ymax) y_1 -= yh; /* check case of yi > y_1 */
if (y_1 < ymin) y_1 += yh; /* check case of yi < y_1 */
y_2 = y_1 + (xmax - xmin) * tan (theta_r);
}
else
{ /* sectors 2, 6 */
sector = 2;
xi = (y_1 - ac_y) * cot (theta_r) + ac_x;
xh = x_sp / sin (theta_r); /* this fails at theta = 0 */
x_off = fmod (x_2 - xi, xh); /* get distance inside of right edge for starting point */
x_1 = xmax - x_off;
if (x_1 > xmax) x_1 -= xh; /* check case of xi > x_1 */
if (x_1 < xmin) x_1 += xh; /* check case of xi < x_1 */
x_2 = x_1 + (ymax - ymin) * cot (theta_r);
}
}
else /* sectors 4,8 */
{
if (theta > 135.0)
{
sector = 4;
yi = (x_2 - ac_x) * tan (theta_r) + ac_y;
yh = - x_sp / cos (theta_r); /* this fails at theta = 90 */
/* get distance above bottom edge for starting point */
y_off = fmod (y_2 - yi, yh);
y_1 = ymax - y_off;
if (y_1 > ymax) y_1 -= yh; /* check case of yi > y_1 */
if (y_1 < ymin) y_1 += yh; /* check case of yi < y_1 */
y_2 = y_1 - (xmax - xmin) * tan (theta_r);
/* tan (theta) < 0 for 90 <= theta < 180 */
xmin = x_2;
xmax = x_1;
}
else
{ /* sectors 3,7 */
sector = 3;
xi = (y_2 - ac_y) * cot (theta_r) + ac_x;
xh = x_sp / sin (theta_r); /* this fails at theta = 0 */
x_off = fmod (x_2 - xi, xh); /* get distance inside of right edge for starting point */
x_1 = xmax - x_off;
if (x_1 > xmax) x_1 -= xh; /* check case of xi > x_1 */
if (x_1 < xmin) x_1 += xh; /* check case of xi < x_1 */
x_2 = x_1 - (ymax - ymin) * cot (theta_r);
ymax = y_1;
ymin = y_2;
}
}
if (x_sp == 0.0) return; /* no point in wasting time */
where (&xlast, &ylast); /* get current position in current units */
n = 0; /* emergency break-out counter */
if (sector == 1 || sector == 4)
{
etan = tan (theta_r);
while (y_2 > ymin && n < 2048) /* this loop only works for 0 <= theta < 90 */
{
++n;
xd1 = xmin;
yd1 = y_1;
xd2 = xmax;
yd2 = y_2;
if (yd2 > ymax)
{
yd2 = ymax;
xd2 = xmin + (yd2 - y_1) / etan;
} /* never reach this case if theta == 0 since */
/* y_1 == y_2 and y_1 < ymax */
if (yd1 < ymin)
{
yd1 = ymin;
xd1 = xmin + (ymin - y_1) / etan;
} /* never reach this case if theta == 0 since y_2 == y_1 */
/* and loop begins with y_1 >= ymin */
if (scaling == ON) /* convert to user units */
{
user_units (&xd1, &yd1);
user_units (&xd2, &yd2);
}
move (xd1, yd1);
draw (xd2, yd2);
y_1 -= yh;
y_2 -= yh;
}
}
else /* sectors 2, 3 */
{
ecot = cot (theta_r);
while (x_2 > xmin && n < 2048) /* this loop decrements x sizes */
{
++n;
xd1 = x_1;
yd1 = ymin;
xd2 = x_2;
yd2 = ymax;
if (xd2 > xmax)
{
xd2 = xmax;
yd2 = ymin + (xd2 - x_1) / ecot;
} /* never reach this case if theta == 0 since */
/* x_1 == x_2 and x_1 < xmax */
if (xd1 < xmin)
{
xd1 = xmin;
yd1 = ymin + (xmin - x_1) / ecot;
} /* never reach this case if theta == 0 since y_2 == y_1 */
/* and loop begins with x_1 >= xmin */
if (scaling == ON) /* revert to user units for drawing */
{
user_units (&xd1, &yd1);
user_units (&xd2, &yd2);
}
move (xd1, yd1);
draw (xd2, yd2);
x_1 -= xh;
x_2 -= xh;
}
}
move (xlast, ylast); /* return to original position */
}
/*-------------------------------------*/
static void solid_rect (double x_1, double y_1, double x_2, double y_2)
{ /* draw solid filled rectangles w/o rotation */
/* passed parameters are in current units */
int x, y, page, c1, c2;
struct scrn_pixel__ pix1, pix2;
DB (printf ("solid_fill: from (%lf,%lf) to (%lf,%lf)\n", x_1, y_1, x_2, y_2);)
/* because there is no filled rectangle in the graphix library, we are
force to make our own here, and call the line drawing portion of the
graphix library directly. That gives the best drawing speed and makes
it possible to prevent line overlap at the pixel level. To do
this, we need to know the clip borders in the current units. We can
use pmap () to retrieve the pixel coordinates of the rectangle corners.
The clipping code used here is a modified Cohen-Sutherland coded clipper.
It returns the clip end-points of a horizontal and a vertical line. If
the x or y end-points are both outside the clip border, then the
entire rectangle must be outside the clip border, and there is nothing
to draw. */
page = 0; /* used by pc_wrt_line (): current graphix page */
/* get pixel coordinates */
pmap (x_1, y_1, (struct scrn_pixel__ _far *) &pix1);
pmap (x_2, y_2, (struct scrn_pixel__ _far *) &pix2);
pix1.yp = __gr_msc__.max_y_dot - pix1.yp; /* pmap () returns true pixel coordinates */
pix2.yp = __gr_msc__.max_y_dot - pix2.yp; /* map to origin in lower left corner */
DB (printf ("solid_fill: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
c1 = code (pix1.xp, pix1.yp);
c2 = code (pix2.xp, pix1.yp);
DB (printf ("c1 = %d, c2 = %d\n", c1, c2);)
if ( c1 & (4 | 8) ) /* test x-coordinates */
{
if ( c1 & 0x8 ) /* x_1 < clip_xmin */
{
if (c2 & 0x8) /* x_2 < clip_xmin */
return; /* both x-coords outside clip border */
pix1.xp = hpgl_clip.xmin;
}
else if ( c1 & 0x4 ) /* x_1 > clip_xmax */
{
if (c2 & 0x04) /* x_2 > clip_xmax */
return; /* both x-coords outside clip border */
pix1.xp = hpgl_clip.xmax;
}
}
if ( c2 ) /* test 2nd x-coordinate */
{
if ( c2 & 0x8 ) /* x_2 < clip_xmin */
{ /* already tested x_1 */
pix2.xp = hpgl_clip.xmin;
}
else if ( c2 & 0x4 ) /* x_2 > clip_xmax */
{ /* already tested x_1 */
pix2.xp = hpgl_clip.xmax;
}
}
c1 = code (pix1.xp, pix1.yp);
c2 = code (pix1.xp, pix2.yp);
DB (printf ("c1 = %d, c2 = %d\n", c1, c2);)
if ( c1 & (1 | 2) )
{
if ( c1 & 0x2 ) /* y_1 < clip_ymin */
{
if (c2 & 0x2) /* y_2 < clip_ymin */
return;
pix1.yp = hpgl_clip.ymin;
}
else if ( c1 & 0x1 ) /* y_1 > clip_ymax */
{
if (c2 & 0x1) /* y_2 > clip_ymax */
return;
pix1.yp = hpgl_clip.ymax;
}
}
if ( c2 ) /* test 2nd y-coordinate */
{
if ( c2 & 0x2 ) /* y_2 < clip_ymin */
{ /* already tested y_1 */
pix2.yp = hpgl_clip.ymin;
}
else if ( c2 & 0x1 ) /* y_2 > clip_ymax */
{ /* already tested y_1 */
pix2.yp = hpgl_clip.ymax;
}
}
DB (printf ("solid_fill: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
/* now limit pixel value to screen size */
pix1.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix1.xp)));
pix1.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix1.yp)));
pix2.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix2.xp)));
pix2.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix2.yp)));
DB (printf ("solid_fill: limited (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
if (pix1.yp > pix2.yp)
{
y = pix1.yp;
pix1.yp = pix2.yp;
pix2.yp = y;
}
for (y = pix1.yp; y <= pix2.yp; ++y) /* draw the solid rectangle */
{
pc_wrt_line (page, pix1.xp, y, pix2.xp, y, my_pen);
} /* my_pen = internal pen color */
return;
}
/*-------------------------------------*/
/*
| 1 |
| |
--------+-------------+---------
| |
8 | OK | 4
| |
--------+-------------+---------
| |
| 2 |
*/
static int code (int x, int y) /* return clipping code */
{
int clip_code;
clip_code = 0;
if (x < hpgl_clip.xmin) clip_code = 8;
else if (x > hpgl_clip.xmax) clip_code = 4;
if (y < hpgl_clip.ymin) clip_code |= 2;
else if (y > hpgl_clip.ymax) clip_code |= 1;
return (clip_code);
} /* returned code: (x < xmin:x > xmax:y < ymin:y > ymax) */
/*-------------------------------------*/
static double cot ( double theta )
{ /* valid from 0 to 180 degrees */
double a;
a = cos (theta);
return ( a * sqrt ( 1.0 - a * a));
}
/*--------------------------------------*/
void chord_t (FILE * infile)
{
double x;
if (get_val (infile, &x))
{
if (x == 1.0)
{
chord_type = LENGTH;
return;
}
if (x != 0.0)
{
print_string ("CT: invalid argument\n");
return;
}
}
chord_type = ANG; /* chord type in degree's */
return;
}
/*--------------------------------------*/
void set_clip (double x_1, double x_2, double y_1, double y_2)
{
struct scrn_pixel__ pix1, pix2;
double px1, px2, py1, py2, tmp;
px1 = p1x;
px2 = p2x;
py1 = p1y;
py2 = p2y;
DB (printf ("set_clip: clip from (%18.11lf,%18.11lf) to (%18.11lf,%18.11lf)\n", x_1, y_1, x_2, y_2);)
DB (printf ("set_clip: hard clip: (p1x, p1y) = (%lf,%lf) to (p2x, p2y) = (%lf,%lf)\n", p1x, p1y, p2x, p2y);)
/* check against P1/P2 window */
if (scaling == ON)
{ /* get user units for "hard clip" border */
user_units (&px1, &py1);
user_units (&px2, &py2);
}
/* limit clipping border to P1/P2 border */
/* this will prevent drawing outside the P1/P2 border when */
/* P1/P2 < paper size and clipping window > P1/P2 border */
/* exchange x_1, x_2 and y_1, y_2 if P1/P2 exchanged */
if (p1x < p2x)
{
x_1 = MAX (px1, x_1);
x_2 = MIN (px2, x_2);
}
else /* P1/P2 exchanged */
{
tmp = MAX (px2, x_2);
x_2 = MIN (px1, x_1);
x_1 = tmp;
}
if (p1y < p2y)
{
y_1 = MAX (py1, y_1);
y_2 = MIN (py2, y_2);
}
else /* P1/P2 exchanged */
{
tmp = MAX (py2, y_2);
y_2 = MIN (py1, y_1);
y_1 = tmp;
}
DB (printf ("set_clip: clip from (%lf,%lf) to (%lf,%lf)\n", x_1, y_1, x_2, y_2);)
clip (x_1, x_2, y_1, y_2); /* clipping limited to P1/P2 window */
/* get pixel coordinates */
pmap (x_1, y_1, (struct scrn_pixel__ _far *) &pix1);
pmap (x_2, y_2, (struct scrn_pixel__ _far *) &pix2);
DB (printf ("set_clip: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
/* now limit pixel value to screen size */
pix1.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix1.xp)));
pix1.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix1.yp)));
pix2.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix2.xp)));
pix2.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix2.yp)));
DB (printf ("set_clip: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
hpgl_clip.xmin = pix1.xp;
hpgl_clip.xmax = pix2.xp;
hpgl_clip.ymin = __gr_msc__.max_y_dot - pix1.yp;
hpgl_clip.ymax = __gr_msc__.max_y_dot - pix2.yp; /* compensate for origin in LL corner */
/* save clip border in pixels for solid_fill () */
DB (printf ("set_clip: hardclip (pixel) (%d,%d) to (%d,%d)\n", hpgl_clip.xmin, hpgl_clip.ymin, hpgl_clip.xmax, hpgl_clip.ymax);)
return;
}
/*--------------------------------------*/